package com.example.maze.swing;

import com.example.maze.model.Cell;
import com.example.maze.model.Coordinate;
import com.example.maze.model.Maze;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * 适配Swing的动画DFS寻路器
 * 
 * @author maze-demo
 */
public class SwingAnimatedDFSSolver implements AnimatedMazeSolver {
    private static final Logger logger = LoggerFactory.getLogger(SwingAnimatedDFSSolver.class);
    
    private int animationDelayMs = 100; // 默认100ms延迟
    
    @Override
    public AnimatedSolverResult solveWithAnimation(Maze maze, Consumer<SolverStep> stepCallback) {
        logger.info("开始使用Swing动画DFS算法寻路");
        
        if (!maze.isValid()) {
            throw new IllegalArgumentException("迷宫无效：缺少起点或终点");
        }

        long startTime = System.currentTimeMillis();
        List<SolverStep> steps = new ArrayList<>();
        
        // 重置迷宫状态
        maze.reset();
        
        // 初始化
        Cell startCell = maze.getStartCell();
        Cell endCell = maze.getEndCell();
        Stack<Cell> stack = new Stack<>();
        Set<Coordinate> visited = new HashSet<>();
        Map<Cell, Cell> parentMap = new HashMap<>();
        
        // 将起点加入栈
        stack.push(startCell);
        visited.add(startCell.getCoordinate());
        int visitedCount = 0;
        
        // 记录开始步骤
        SolverStep startStep = SolverStep.start("DFS算法开始寻路");
        steps.add(startStep);
        callbackStep(stepCallback, startStep);
        
        logger.debug("DFS开始: 起点={}, 终点={}", startCell.getCoordinate(), endCell.getCoordinate());
        
        // DFS主循环
        boolean found = false;
        while (!stack.isEmpty() && !found) {
            Cell current = stack.pop();
            visitedCount++;
            
            // 标记当前单元格为已访问（用于可视化）
            if (current.getType() == Cell.Type.PATH) {
                current.setType(Cell.Type.VISITED);
            }
            
            // 记录访问步骤
            SolverStep visitStep = SolverStep.visit(current.getCoordinate(), 
                String.format("访问节点 (%d,%d)", current.getCoordinate().getRow(), current.getCoordinate().getCol()));
            steps.add(visitStep);
            callbackStep(stepCallback, visitStep);
            
            logger.trace("DFS访问: {}", current.getCoordinate());
            
            // 检查是否到达终点
            if (current.equals(endCell)) {
                found = true;
                logger.debug("DFS找到终点: {}", current.getCoordinate());
                break;
            }
            
            // 获取所有可通行的邻居
            List<Cell> neighbors = maze.getPassableNeighbors(current);
            
            // 随机打乱邻居顺序，增加路径的随机性
            Collections.shuffle(neighbors);
            
            // 将未访问的邻居加入栈
            for (Cell neighbor : neighbors) {
                Coordinate neighborCoord = neighbor.getCoordinate();
                
                if (!visited.contains(neighborCoord)) {
                    visited.add(neighborCoord);
                    stack.push(neighbor);
                    parentMap.put(neighbor, current);
                    
                    logger.trace("DFS加入栈: {}", neighborCoord);
                }
            }
        }
        
        long endTime = System.currentTimeMillis();
        long timeMillis = endTime - startTime;
        
        if (found) {
            // 重建路径
            List<Coordinate> path = reconstructPath(parentMap, startCell, endCell);
            
            // 记录解路径步骤
            for (Coordinate coord : path) {
                if (!coord.equals(startCell.getCoordinate()) && !coord.equals(endCell.getCoordinate())) {
                    SolverStep solutionStep = SolverStep.solution(coord, 
                        String.format("解路径节点 (%d,%d)", coord.getRow(), coord.getCol()));
                    steps.add(solutionStep);
                    callbackStep(stepCallback, solutionStep);
                }
            }
            
            logger.info("DFS寻路成功: 路径长度={}, 访问节点={}, 耗时={}ms", 
                path.size(), visitedCount, timeMillis);
            
            // 记录结束步骤
            SolverStep endStep = SolverStep.end("DFS算法寻路成功完成");
            steps.add(endStep);
            callbackStep(stepCallback, endStep);
            
            return new AnimatedSolverResult("DFS", path, visitedCount, timeMillis, steps);
        } else {
            logger.info("DFS寻路失败: 访问节点={}, 耗时={}ms", visitedCount, timeMillis);
            
            // 记录结束步骤
            SolverStep endStep = SolverStep.end("DFS算法寻路失败");
            steps.add(endStep);
            callbackStep(stepCallback, endStep);
            
            return AnimatedSolverResult.notFound("DFS", visitedCount, timeMillis, steps);
        }
    }
    
    /**
     * 调用步骤回调函数
     */
    private void callbackStep(Consumer<SolverStep> stepCallback, SolverStep step) {
        if (stepCallback != null) {
            stepCallback.accept(step);
            
            // 添加动画延迟
            if (animationDelayMs > 0) {
                try {
                    Thread.sleep(animationDelayMs);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    logger.warn("动画延迟被中断", e);
                }
            }
        }
    }
    
    /**
     * 重建从起点到终点的路径
     */
    private List<Coordinate> reconstructPath(Map<Cell, Cell> parentMap, Cell start, Cell end) {
        List<Coordinate> path = new ArrayList<>();
        Cell current = end;
        
        // 从终点向起点回溯
        while (current != null) {
            path.add(current.getCoordinate());
            current = parentMap.get(current);
        }
        
        // 反转路径，使其从起点到终点
        Collections.reverse(path);
        
        logger.debug("DFS重建路径: {} 个节点", path.size());
        return path;
    }
    
    @Override
    public String getName() {
        return "DFS";
    }
    
    @Override
    public void setAnimationDelay(int delayMs) {
        this.animationDelayMs = Math.max(0, delayMs);
    }
    
    @Override
    public int getAnimationDelay() {
        return animationDelayMs;
    }
}